package com.shycloud.mido.organ.controller;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jdom.JDOMException;
import org.slf4j.helpers.MessageFormatter;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.shycloud.common.minio.service.MinioTemplate;
import com.shycloud.mido.common.core.constant.CommonConstants;
import com.shycloud.mido.common.core.exception.BusinessException;
import com.shycloud.mido.common.core.util.R;
import com.shycloud.mido.common.pay.wxpay.WXPay;
import com.shycloud.mido.common.pay.wxpay.utils.WxConfigUtil;
import com.shycloud.mido.member.api.util.UUIDUtil;
import com.shycloud.mido.organ.api.dto.LiveRoomAttachmentDTO;
import com.shycloud.mido.organ.api.dto.LiveRoomDTO;
import com.shycloud.mido.organ.api.dto.LiveRoomInsertDTO;
import com.shycloud.mido.organ.api.entity.LiveMemberEnterEntity;
import com.shycloud.mido.organ.api.entity.LiveMemberViewEntity;
import com.shycloud.mido.organ.api.entity.LiveRoomAttachment;
import com.shycloud.mido.organ.api.entity.LiveRoomAttachmentImage;
import com.shycloud.mido.organ.api.entity.LiveRoomEntity;
import com.shycloud.mido.organ.api.entity.MiniMessage;
import com.shycloud.mido.organ.api.vo.MsgSecCheckVO;
import com.shycloud.mido.organ.config.LiveProperties;
import com.shycloud.mido.organ.mapper.LiveMemberEnterMapper;
import com.shycloud.mido.organ.mapper.LiveMemberViewMapper;
import com.shycloud.mido.organ.mapper.LiveRoomMapper;
import com.shycloud.mido.organ.mapper.MemberMapper;
import com.shycloud.mido.organ.mapper.MessageMapper;
import com.shycloud.mido.organ.mapper.StudentDetailedMapper;
import com.shycloud.mido.organ.service.LiveRoomAttachmentImageService;
import com.shycloud.mido.organ.service.LiveRoomAttachmentService;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.util.Base64;

/**
 * 小程序直播间 controller
 *
 * @author nianhua.jiang 交接
 * @date 2021/2/22 16:12
 **/
@RestController
@AllArgsConstructor
@RequestMapping("/live")
@Slf4j
public class LiveRoomController {

	/** 直播间模块 mapper */
	private LiveRoomMapper liveRoomMapper;
	/** 直播间是否可见 mapper */
	private LiveMemberViewMapper viewMapper;
	/** 直播间是否收费 mapper */
	private LiveMemberEnterMapper enterMapper;
	/** 用户模块 mapper */
	private MemberMapper memberMapper;
	/** 学生模块 mapper */
	private StudentDetailedMapper studentMapper;
	/** 七牛云工具类 */
	private MinioTemplate minioTemplate;
	/** redis 缓存工具类 */
	private RedisTemplate redisTemplate;
	/** LiveProperties */
	private LiveProperties liveProperties;

	private LiveRoomAttachmentService liveRoomAttachmentService;

	private LiveRoomAttachmentImageService liveRoomAttachmentImageService;

	private MessageMapper messageMapper;

	/**
	 * 测试用接口
	 *
	 * @return {@link R}
	 * @author nianhua.jiang
	 * @date 2021/2/22 16:14
	 **/
	@GetMapping("/getRoomList")
	public R getRoomList() {
		QueryWrapper<LiveRoomEntity> queryWrapper = new QueryWrapper<>();
		return new R<>(liveRoomMapper.selectList(queryWrapper));
	}

	/**
	 * 通过用户ID获取直播间列表
	 *
	 * @return {@link R}
	 * @author nianhua.jiang
	 * @date 2021/2/22 16:14
	 **/
	@GetMapping("/getRoomListByMemberId")
	public R getRoomListByMemberId(String memberId) {
		QueryWrapper<LiveRoomEntity> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("member_id", memberId);
		return new R<>(liveRoomMapper.selectList(queryWrapper));
	}

	/**
	 * 直播间分享
	 *
	 * @param memberId 用户ID
	 * @param roomId   直播间ID
	 * @return {@link R}
	 * @author nianhua.jiang
	 * @date 2021/2/22 16:21
	 **/
	@GetMapping("/addRoomViewPermissions")
	public R addRoomViewPermissions(String memberId, String roomId) {
		QueryWrapper<LiveMemberViewEntity> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("liveroom_id", roomId);
		queryWrapper.eq("member_id", memberId);
		if (viewMapper.selectList(queryWrapper).size() == 0) {
			LiveMemberViewEntity lmView = new LiveMemberViewEntity();
			lmView.setLiveroomId(roomId);
			lmView.setMemberId(memberId);
			return new R<>(lmView.insert());
		}
		return new R<>(0);
	}

	/**
	 * 获取被邀请的直播间列表
	 *
	 * @param page     分页参数
	 * @param memberId 会员 ID
	 * @return {@link R}
	 * @author nianhua.jiang
	 * @date 2021/2/22 16:27
	 **/
	@GetMapping("/getInvitedRoomPage")
	public R getInvitedRoomPage(Page<LiveRoomDTO> page, String memberId, String name) {

		//分页查询此用户可见的直播间
		IPage<LiveRoomDTO> result = liveRoomMapper.getInvitedRoomPage(page, memberId, name);
		//取出数据进行最后处理
		for (LiveRoomDTO dto : result.getRecords()) {
			//收费逻辑
//			QueryWrapper queryWrapper = new QueryWrapper<>();
//			queryWrapper.eq("member_id", memberId);
//			queryWrapper.eq("liveroom_id", dto.getId());
//			if (enterMapper.selectList(queryWrapper).size() > 0) {
//				dto.setType("0");
//			}
			//显示是否正在直播的逻辑
			DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
			LocalDateTime startTime = LocalDateTime.parse(dto.getStartTime(), dateTimeFormatter);
			LocalDateTime endTime = LocalDateTime.parse(dto.getEndTime(), dateTimeFormatter);
			LocalDateTime now = LocalDateTime.now();
			//+8小时暂时修复时区问题
			//now = now.plusHours(8);
			if (now.isBefore(startTime)) {
				dto.setIsLiving("0");
			} else if (now.isAfter(endTime)) {
				dto.setIsLiving("2");
			} else {
				dto.setIsLiving("1");
			}
			//处理是否有密码状态
			if (StringUtils.isNotBlank(dto.getPassword())) {
				dto.setPassword("1");
			} else {
				dto.setPassword("0");
			}
		}
		return new R<>(result);
	}

	@GetMapping("/getInvitedRecordRoomPage")
	public R getInvitedRecordRoomPage(Page<LiveRoomDTO> page) {

		IPage<LiveRoomDTO> result = liveRoomMapper.getInvitedRecordRoomPage(page);
		return new R<>(result);
	}

	@GetMapping("/getRoomPage")
	public R getRoomPage(Page<LiveRoomEntity> page) {
		return new R<>(liveRoomMapper.getRoomPage(page));
	}

	@GetMapping("/getMyRoomPage")
	public R getMyRoomPage(Page<LiveRoomEntity> page, String memberId) {
		IPage<LiveRoomDTO> result = liveRoomMapper.getMyRoomPage(page, memberId);
		for (LiveRoomDTO dto : result.getRecords()) {
			//显示是否正在直播的逻辑
			DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
			LocalDateTime startTime = LocalDateTime.parse(dto.getStartTime(), dateTimeFormatter);
			LocalDateTime endTime = LocalDateTime.parse(dto.getEndTime(), dateTimeFormatter);
			LocalDateTime now = LocalDateTime.now();
			//+8小时暂时修复时区问题
			//now = now.plusHours(8);
			if (now.isBefore(startTime)) {
				dto.setIsLiving("0");
			} else if (now.isAfter(endTime)) {
				dto.setIsLiving("2");
			} else {
				dto.setIsLiving("1");
			}
		}
		return new R<>(result);
	}

	@GetMapping("/checkPermissionPusher")
	public R checkPermissionPusher(String memberId, String roomId) {
		//可以提前半个小时进入
		LiveRoomEntity room = liveRoomMapper.selectById(roomId);
		DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		LocalDateTime startTime = LocalDateTime.parse(room.getStartTime(), dateTimeFormatter);
		LocalDateTime now = LocalDateTime.now();
		//+8小时暂时修复时区问题
		//now = now.plusHours(8);
		LocalDateTime time = startTime.minusMinutes(31);
		if (now.isAfter(time)) {
			return new R<>(true);
		} else {
			return new R<>(false);
		}
	}

	/**
	 * 观众进入直播间时的校验
	 *
	 * @param memberId 用户ID
	 * @param roomId   直播间ID
	 * @param password 密码
	 * @return
	 * @author nianhua.jiang
	 * @date 2021/2/22 16:47
	 **/
	@GetMapping("/checkPermissions")
	public R checkPermissions(String memberId, String roomId, String password) {

		//增加返回状态  -1:默认状态, 0:正常, 1:没有进入权限, 2:密码错误, 3:未到开播时间
		Integer status = -1;
		LiveRoomEntity room = liveRoomMapper.selectById(roomId);
		DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		LocalDateTime startTime = LocalDateTime.parse(room.getStartTime(), dateTimeFormatter);
		LocalDateTime now = LocalDateTime.now();
		//+8小时暂时修复时区问题
		//now = now.plusHours(8);
		LocalDateTime time = startTime.minusMinutes(31);
		//判断是否有进入权限
		Boolean enter = false;
		Boolean pwd = false;
		//判断是否到了直播时间
		Boolean open = false;
		if (now.isAfter(time)) {
			open = true;
		} else {
			status = 3;
		}
//		if (room.getType().equals("1")) {
//			//收费
//			QueryWrapper queryWrapper = new QueryWrapper<>();
//			queryWrapper.eq("member_id", memberId);
//			queryWrapper.eq("liveroom_id", roomId);
//			if (enterMapper.selectList(queryWrapper).size() > 0) {
//				enter = true;
//			} else {
//				status = 1;
//			}
//		} else {
//			enter = true;
//		}
		enter = true;
		if (StringUtils.isNotBlank(room.getPassword())) {
			//有密码
			if (room.getPassword().equals(password)) {
				pwd = true;
			} else {
				status = 2;
			}
		} else {
			pwd = true;
		}
		if (enter && pwd && open) {
			//如果有进入权限切密码正确
			status = 0;
			return new R(status);
		} else {
			return new R(status);
		}
	}

	@PostMapping("/wxPay")
	public R wxPay(@RequestBody Map<String, String> map, HttpServletRequest request) {
		String roomId = map.get("id");
		LiveRoomEntity room = liveRoomMapper.selectById(roomId);
		String memberId = map.get("memberId");
		Random r = new Random();
		String orderId = "";
		for (int i = 1; i < 8; i++) {
			orderId += r.nextInt(9); // 生成[0,9]区间的整数
		}
		return new R<>(
				WXPay.miniPrePay(WxConfigUtil.MINI_APP_ID, room.getPrice(), "快乐斑马小程序" + room.getName(),
						memberMapper.selectById(memberId).getWxMiniOpenId(),
						"http://api.joymido.com/organization/live/wxNotify", orderId, request));
	}

	@Transactional(rollbackFor = Exception.class)
	@PostMapping("/wxNotify")
	public R wxNotify(HttpServletRequest request, HttpServletResponse response) {
		request.getRequestURI();
		try {
			//微信支付操作
			Map<String, String> map = WXPay.wxNotify(request, response);
			return new R<>(map);
		} catch (IOException e) {
			throw new BusinessException("微信支付回调处理异常！");
		} catch (JDOMException e) {
			throw new BusinessException("微信支付回调处理异常！");
		} catch (BusinessException e) {
			throw e;
		} catch (Exception e) {
			throw new BusinessException("微信支付回调处理异常！");
		}
	}


	@ApiOperation("上传直播间文件")
	@PostMapping("/uploadRoomFile")
	public R uploadRoomFile(@RequestParam(value = "files") List<MultipartFile> files) {

		List<String> resultUrl = new ArrayList<>();

		try {
			for (MultipartFile file : files) {
				//判断PDF
				if (!StringUtils.equals("pdf", FilenameUtils.getExtension(file.getOriginalFilename()).toLowerCase())) {
					return new R(CommonConstants.FAIL, "只能上传PDF文件", false);
				}
				String url = minioTemplate.uploadFileCdn(file.getInputStream(), UUIDUtil.getUUID32() + "_" +
						file.getOriginalFilename(), liveProperties.getBucket(), liveProperties.getCdn());
				resultUrl.add(url);
			}
		} catch (IOException e) {
			return new R(CommonConstants.FAIL, e.getLocalizedMessage(), false);
		}
		return new R(resultUrl);
	}

	//后台用接口
	@ApiOperation("创建直播（前端需要传MEMBERID 后台为手机号并且MEMBERID为空）")
	@PostMapping("/addRoom")
	public R addRoom(@RequestBody LiveRoomInsertDTO room) throws Exception {

		liveRoomAttachmentService.addRoom(room);

//
		return new R<>("创建直播间成功，请等待后台人员审核。");
	}


	@GetMapping("/getRoomDetail")
	public R getRoomDetail(String roomId) {
		LiveRoomDTO dto = liveRoomMapper.getRoomDetail(roomId);
		if (StringUtils.isNotBlank(dto.getPassword())) {
			dto.setPassword("1");
		} else {
			dto.setPassword("0");
		}
		return new R<>(dto);
	}

	@GetMapping("/getRoomPageAdmin")
	public R getRoomPageAdmin(Page<LiveRoomEntity> page, String name, String type) {
		// QueryWrapper queryWrapper = new QueryWrapper<>();
		// if(StringUtils.isNotBlank(name)){
		//     queryWrapper.like("name", name);
		// }
		// if(StringUtils.isNotBlank(type)){
		//     queryWrapper.eq("type", type);
		// }
		// liveRoomMapper.selectPage(page, queryWrapper);
		return new R<>(liveRoomMapper.getRoomPageAdmin(page, name, type));
	}

	@GetMapping("/verifyPusherAccount")
	public R verifyPusherAccount(String phone) {
		QueryWrapper queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("username", phone);
		if (memberMapper.selectList(queryWrapper).size() == 1) {
			return new R<>(true);
		} else {
			return new R<>(false);
		}
	}

	@GetMapping("/getOrgOrOptList")
	public R getOrgOrOptList(String type) {
		//0: 用户列表, 1: 机构, 2:运营商
		if (type.equals("1")) {
			return new R<>(liveRoomMapper.getOrgList());
		}
		if (type.equals("2")) {
			return new R<>(liveRoomMapper.getOptList());
		}
		return new R<>();
	}

	@GetMapping("/disableRoom")
	public R disableRoom(String roomId) {
		LiveRoomEntity room = new LiveRoomEntity();
		room.setId(roomId);
		room.setIsDisable("1");
		return new R<>(liveRoomMapper.updateById(room));
	}

	@GetMapping("/enableRoom")
	public R enableRoom(String roomId) {
		LiveRoomEntity room = new LiveRoomEntity();
		room.setId(roomId);
		room.setIsDisable("0");
		return new R<>(liveRoomMapper.updateById(room));
	}

	/**
	 * 显示附件0显示1不显示
	 *
	 * @param roomId
	 * @param showAttachment
	 * @return
	 * @Description: updateRoom
	 * @author baiqiang.
	 * @date 2021年7月30日 下午1:02:32
	 * @version V1.0
	 */
	@ApiOperation("显示附件0显示1不显示")
	@GetMapping("/updateShowAttachment")
	public R updateRoom(String roomId, String showAttachment) {
		LiveRoomEntity room = new LiveRoomEntity();
		room.setId(roomId);
		room.setShowAttachment(showAttachment);
		return new R<>(liveRoomMapper.updateById(room));
	}

	@SneakyThrows
	@Transactional
	@GetMapping("/deleteRoom")
	public R deleteRoom(String roomId) {

		LiveRoomEntity liveRoomEntity = liveRoomMapper.selectById(roomId);

		String shareImgUrl = liveRoomEntity.getShareImgUrl();

		if (StringUtils.isNotEmpty(shareImgUrl)) {
			// 删除七牛云文件
			minioTemplate.delete("cover-img", shareImgUrl.replace("http://cover.img.joymido.com/", ""));
		}

		liveRoomMapper.deleteById(roomId);
		//删除关联的直播间数据
		QueryWrapper<LiveMemberViewEntity> queryWrapper = new QueryWrapper<>();
		queryWrapper.eq("liveroom_id", roomId);
		LiveMemberViewEntity lmView = new LiveMemberViewEntity();
		lmView.delete(queryWrapper);

		QueryWrapper<LiveMemberEnterEntity> queryWrapper2 = new QueryWrapper<>();
		queryWrapper2.eq("liveroom_id", roomId);
		LiveMemberEnterEntity lmEnter = new LiveMemberEnterEntity();
		lmEnter.delete(queryWrapper2);

		return new R<>(true);
	}

	/**
	 * 直播间 禁言/解禁
	 *
	 * @param isTalking true-解除禁言 false-禁言
	 * @return com.shycloud.mido.common.core.util.R
	 * @author nianhua.jiang
	 * @date 2021/4/9 15:17
	 **/
	@GetMapping("roomSpeak")
	public R roomSpeak(String roomId, boolean isTalking) {
		redisTemplate.delete("mini_talkingFlg:" + roomId);
		redisTemplate.opsForValue().set("mini_talkingFlg:" + roomId, isTalking, 1, TimeUnit.DAYS);
		return new R(true);
	}

	/**
	 * 直播间 获取禁言状态
	 *
	 * @param roomId 直播间ID
	 * @return com.shycloud.mido.common.core.util.R
	 * @author nianhua.jiang
	 * @date 2021/4/9 15:17
	 **/
	@GetMapping("getRoomSpeak")
	public R getRoomSpeak(String roomId) {

		if (redisTemplate.opsForValue().get("mini_talkingFlg:" + roomId) == null) {
			redisTemplate.opsForValue().set("mini_talkingFlg:" + roomId, true, 1, TimeUnit.DAYS);
		}
		LiveRoomInsertDTO liveRoomDTO = new LiveRoomInsertDTO();
		LiveRoomEntity liveRoomEntity = liveRoomMapper.selectById(roomId);
		BeanUtils.copyProperties(liveRoomEntity, liveRoomDTO);
		liveRoomDTO.setMiniTalkingFlg(redisTemplate.opsForValue().get("mini_talkingFlg:" + roomId));

		LiveRoomAttachment attachment = liveRoomAttachmentService
				.getOne(Wrappers.<LiveRoomAttachment>lambdaQuery().eq(LiveRoomAttachment::getLiveroomId, roomId).last("limit 1"));
		if (Objects.nonNull(attachment)) {
			List<LiveRoomAttachmentDTO> attachmentList = new ArrayList<LiveRoomAttachmentDTO>();

			LiveRoomAttachmentDTO liveRoomAttachmentDTO = new LiveRoomAttachmentDTO();

			BeanUtils.copyProperties(attachment, liveRoomAttachmentDTO);
			List<LiveRoomAttachmentImage> imagelist = liveRoomAttachmentImageService
					.list(Wrappers.<LiveRoomAttachmentImage>lambdaQuery()
							.eq(LiveRoomAttachmentImage::getLiveroomId, roomId)
							.eq(LiveRoomAttachmentImage::getAttachmentId, attachment.getId())
							.orderByAsc(LiveRoomAttachmentImage::getSort));
			if (CollectionUtils.isNotEmpty(imagelist)) {
				liveRoomAttachmentDTO.setLiveRoomAttachmentImageList(imagelist);
			}
			attachmentList.add(liveRoomAttachmentDTO);
			liveRoomDTO.setAttachmentList(attachmentList);
		}
		return new R(liveRoomDTO);
	}

	@GetMapping("getRoomMemberCount")
	public R getRoomMemberCount(String appid, String channelName) throws Exception {
		// 客户 ID
		final String customerKey = "6020c34bcaa1463d888f8d013b2f5202";
		// 客户密钥
		final String customerSecret = "d81ff80fa9c74cf5b40d625cfad390fd";

		// 拼接客户 ID 和客户密钥并使用 base64 编码
		String plainCredentials = customerKey + ":" + customerSecret;
		String base64Credentials = new String(Base64.getEncoder().encode(plainCredentials.getBytes()));
		// 创建 authorization header
		String authorizationHeader = "Basic " + base64Credentials;
		String url = "https://api.agora.io/dev/v1/channel/user/" + appid + "/" + channelName;

		@SuppressWarnings("deprecation")
		HttpClient httpclient = new DefaultHttpClient();
		HttpGet httpget = new HttpGet(url);
		httpget.setHeader("Authorization", authorizationHeader);
		httpget.setHeader("Content-Type", "application/json");
		HttpResponse response = httpclient.execute(httpget);
		StatusLine statusLine = response.getStatusLine();//获取请求对象中的响应行对象
		int responseCode = statusLine.getStatusCode();//从状态行中获取状态码
		if (responseCode == 200) {
			String responseContent = EntityUtils.toString(response.getEntity(), Consts.UTF_8.name());
			JSONObject parseObj = JSONUtil.parseObj(responseContent);
			log.debug("room info:{}", responseContent);
			//{"success":true,"data":{"channel_exist":true,"mode":2,"broadcasters":[130038824],"audience":[],"audience_total":0}}
			if (null == parseObj || null == parseObj.getJSONObject("data") || null == parseObj.getJSONObject("data")
					.getJSONArray("broadcasters")) {
				return new R(CommonConstants.FAIL, "调用失败", -1);
			}
			return new R(parseObj.getJSONObject("data").getJSONArray("broadcasters").size());
		}
		return new R(CommonConstants.FAIL, "调用失败", -1);
	}


	@GetMapping("getRoomMemberDetail")
	public R getRoomMemberDetail(String appid, String channelName) throws Exception {
		// 客户 ID
		final String customerKey = "6020c34bcaa1463d888f8d013b2f5202";
		// 客户密钥
		final String customerSecret = "d81ff80fa9c74cf5b40d625cfad390fd";

		// 拼接客户 ID 和客户密钥并使用 base64 编码
		String plainCredentials = customerKey + ":" + customerSecret;
		String base64Credentials = new String(Base64.getEncoder().encode(plainCredentials.getBytes()));
		// 创建 authorization header
		String authorizationHeader = "Basic " + base64Credentials;
		String url = "https://api.agora.io/dev/v1/channel/user/" + appid + "/" + channelName;

		@SuppressWarnings("deprecation")
		HttpClient httpclient = new DefaultHttpClient();
		HttpGet httpget = new HttpGet(url);
		httpget.setHeader("Authorization", authorizationHeader);
		httpget.setHeader("Content-Type", "application/json");
		HttpResponse response = httpclient.execute(httpget);
		StatusLine statusLine = response.getStatusLine();//获取请求对象中的响应行对象
		int responseCode = statusLine.getStatusCode();//从状态行中获取状态码
		if (responseCode == 200) {
			String responseContent = EntityUtils.toString(response.getEntity(), Consts.UTF_8.name());
			JSONObject parseObj = JSONUtil.parseObj(responseContent);
			log.debug("room info:{}", responseContent);
			//{"success":true,"data":{"channel_exist":true,"mode":2,"broadcasters":[130038824],"audience":[],"audience_total":0}}
			if (null == parseObj || null == parseObj.getJSONObject("data") || null == parseObj.getJSONObject("data")
					.getJSONArray("broadcasters")) {
				return new R(CommonConstants.FAIL, "调用失败", -1);
			}
			return new R(parseObj.getJSONObject("data"));
		}
		return new R(CommonConstants.FAIL, "调用失败", -1);
	}

	@GetMapping("getRoomMemberStatus")
	public R getRoomMemberStatus(String appid, String uid, String channelName) throws Exception {
		// 客户 ID
		final String customerKey = "6020c34bcaa1463d888f8d013b2f5202";
		// 客户密钥
		final String customerSecret = "d81ff80fa9c74cf5b40d625cfad390fd";

		// 拼接客户 ID 和客户密钥并使用 base64 编码
		String plainCredentials = customerKey + ":" + customerSecret;
		String base64Credentials = new String(Base64.getEncoder().encode(plainCredentials.getBytes()));
		// 创建 authorization header
		String authorizationHeader = "Basic " + base64Credentials;
		String url = "https://api.agora.io/dev/v1/channel/user/property/" + appid + "/" + uid + "/" + channelName;
		///dev/v1/channel/user/property/{appid}/{uid}/{channelName}
		@SuppressWarnings("deprecation")
		HttpClient httpclient = new DefaultHttpClient();
		HttpGet httpget = new HttpGet(url);
		httpget.setHeader("Authorization", authorizationHeader);
		httpget.setHeader("Content-Type", "application/json");
		HttpResponse response = httpclient.execute(httpget);
		StatusLine statusLine = response.getStatusLine();//获取请求对象中的响应行对象
		int responseCode = statusLine.getStatusCode();//从状态行中获取状态码
		if (responseCode == 200) {
			String responseContent = EntityUtils.toString(response.getEntity(), Consts.UTF_8.name());
			JSONObject parseObj = JSONUtil.parseObj(responseContent);
			return new R<>(parseObj);
		}
		return new R(CommonConstants.FAIL, "调用失败", null);
	}

	@PostMapping("msgSecCheck")
	@Deprecated
	public R msgSecCheck(@RequestBody MsgSecCheckVO vo) throws Exception {

		String urlToken = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
				WxConfigUtil.MINI_APP_ID, WxConfigUtil.MINI_APP_SECRET);
		String result = HttpUtil.get(urlToken);
		System.out.println("=========================微信响应报文:{" + result + "}");
		String token = JSONUtil.parseObj(result).get("access_token").toString();
		if (StringUtils.isBlank(token)) {
			return new R(CommonConstants.FAIL, "调用失败", null);
		}
		vo.setAccessToken(token);

		String url = "https://api.weixin.qq.com/wxa/msg_sec_check?access_token=" + vo.getAccessToken();
		CloseableHttpClient httpClient = HttpClients.createDefault();
		HttpPost httpPost = new HttpPost(url);
		httpPost.setHeader("Accept", "application/json");
		httpPost.setHeader("Content-Encoding", "UTF-8");
		httpPost.setHeader("Content-Type", "application/json; charset=UTF-8");

		JSONObject postData = new JSONObject();
		//设置要检测的内容
		postData.put("content", vo.getContent());
		String jsonString = postData.toString();
		httpPost.setEntity(new StringEntity(jsonString, "utf-8"));

		HttpResponse response = httpClient.execute(httpPost);
		StatusLine statusLine = response.getStatusLine();//获取请求对象中的响应行对象
		int responseCode = statusLine.getStatusCode();//从状态行中获取状态码
		if (responseCode == 200) {
			String responseContent = EntityUtils.toString(response.getEntity(), Consts.UTF_8.name());
			JSONObject parseObj = JSONUtil.parseObj(responseContent);
			return new R<>(parseObj);
		}
		return new R(CommonConstants.FAIL, "调用失败", null);
	}

	@PostMapping("msgSecCheckV1")
	public R msgSecCheckV1(@RequestBody MsgSecCheckVO vo) throws Exception {
		String urlToken = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
				WxConfigUtil.MINI_APP_ID, WxConfigUtil.MINI_APP_SECRET);
		String result = HttpUtil.get(urlToken);
		System.out.println("=========================微信响应报文:{" + result + "}");
		String token = JSONUtil.parseObj(result).get("access_token").toString();
		if (StringUtils.isBlank(token)) {
			return new R(CommonConstants.FAIL, "调用失败", null);
		}
		vo.setAccessToken(token);

		String url = "https://api.weixin.qq.com/wxa/msg_sec_check?access_token=" + vo.getAccessToken();
		CloseableHttpClient httpClient = HttpClients.createDefault();
		HttpPost httpPost = new HttpPost(url);
		httpPost.setHeader("Accept", "application/json");
		httpPost.setHeader("Content-Encoding", "UTF-8");
		httpPost.setHeader("Content-Type", "application/json; charset=UTF-8");

		JSONObject postData = new JSONObject();
		//设置要检测的内容
		postData.put("content", vo.getContent());
		String jsonString = postData.toString();
		httpPost.setEntity(new StringEntity(jsonString, "utf-8"));

		HttpResponse response = httpClient.execute(httpPost);
		StatusLine statusLine = response.getStatusLine();//获取请求对象中的响应行对象
		int responseCode = statusLine.getStatusCode();//从状态行中获取状态码
		if (responseCode == 200) {
			String responseContent = EntityUtils.toString(response.getEntity(), Consts.UTF_8.name());
			JSONObject parseObj = JSONUtil.parseObj(responseContent);
			return new R<>(parseObj);
		}
		return new R(CommonConstants.FAIL, "调用失败", null);
	}

	@ApiOperation("审核状态更新 只传 id,status(0:未审核, 1:通过, 2:拒绝)")
	@PostMapping("/updateStatus")
	@Transactional
	public R updateStatus(@RequestBody LiveRoomInsertDTO room) {
		LiveRoomEntity po = liveRoomMapper.selectById(room.getId());
		po.setStatus(room.getStatus());
		liveRoomMapper.updateById(po);
		//消息通知
		MiniMessage miniMessage = new MiniMessage();
		miniMessage.setCreateTime(new Date());
		miniMessage.setMemberId(po.getMemberId());
		miniMessage.setStatus(0);
		String statusMsg = "";
		if ("1".equals(room.getStatus())) {
			statusMsg = "成功审核通过";
		} else {
			statusMsg = "未能通过审核";
		}
		miniMessage.setText(
				MessageFormatter.arrayFormat("亲爱的用户, 您创建的直播间 ( 名称:{} ), {}.", new String[]{po.getName(), statusMsg}).getMessage());
		messageMapper.insert(miniMessage);
		return new R<>(true);
	}

	@GetMapping("bindRoomUid")
	public R bindRoomUid(String roomId, String uid) throws Exception {
		redisTemplate.opsForValue().set("live:room:" + roomId, uid, 2, TimeUnit.DAYS);
		return new R(true);
	}

	@GetMapping("delRoomUid")
	public R delRoomUid(String roomId) throws Exception {
		redisTemplate.delete("live:room:" + roomId);
		return new R(true);
	}

	@GetMapping("getRoomUid")
	public R getRoomUid(String roomId) throws Exception {
		if (redisTemplate.opsForValue().get("live:room:" + roomId) == null) {
			return new R(CommonConstants.SUCCESS, "没有开播", null);
		}
		return new R(redisTemplate.opsForValue().get("live:room:" + roomId));
	}

	@GetMapping("addOrSubRoomMemberCountV2")
	public R addOrSubRoomMemberCount(String roomId, Long num) throws Exception {
		Object obj = redisTemplate.opsForValue().get("live:count:" + roomId);
		if (Objects.isNull(obj)) {
			if (num < 0L) {
				redisTemplate.opsForValue().set("live:count:" + roomId, 0L, 2, TimeUnit.DAYS);
				return new R(0L);
			} else {
				redisTemplate.opsForValue().set("live:count:" + roomId, num, 2, TimeUnit.DAYS);
				return new R(num);
			}
		}
		Long count = (Long) obj;
		Long result = count + num;
		if (result < 0L) {
			redisTemplate.opsForValue().set("live:count:" + roomId, 0L, 2, TimeUnit.DAYS);
			return new R(0L);
		} else {
			redisTemplate.opsForValue().set("live:count:" + roomId, result, 2, TimeUnit.DAYS);
			return new R(result);
		}
	}

	@GetMapping("addOrSubRoomMemberCountV3")
	public R addOrSubRoomMemberCountV3(String roomId, Long num, String memberId, String showname) throws Exception {

		//RLock lock = redissonClient.getLock("addOrSubRoomMemberCountV3");

		//lock.lock(2, TimeUnit.SECONDS);

		//存入用户信息
		Object objDetail = redisTemplate.opsForValue().get("live:memberDetail:" + roomId);

		LiveMemberViewEntity liveMemberView = new LiveMemberViewEntity();
		liveMemberView.setLiveroomId(roomId);
		liveMemberView.setMemberId(memberId);
		liveMemberView.setShowname(showname);

		if (Objects.isNull(objDetail)) {

			if (num > 0) {
				List<LiveMemberViewEntity> liveMemberViews = new ArrayList<>();
				liveMemberViews.add(liveMemberView);
				redisTemplate.opsForValue().set("live:memberDetail:" + roomId, liveMemberViews, 2, TimeUnit.DAYS);
			}

		} else {
			List<LiveMemberViewEntity> liveMemberViews = (List<LiveMemberViewEntity>) objDetail;
			if (num > 0) {
				liveMemberViews.add(liveMemberView);
				redisTemplate.opsForValue().set("live:memberDetail:" + roomId, liveMemberViews, 2, TimeUnit.DAYS);
			} else {
				List<LiveMemberViewEntity> collect = liveMemberViews.stream()
						.filter(x -> !StringUtils.equals(x.getMemberId(), memberId)).collect(Collectors.toList());
				redisTemplate.opsForValue().set("live:memberDetail:" + roomId, collect, 2, TimeUnit.DAYS);
			}
		}

		Object obj = redisTemplate.opsForValue().get("live:count:" + roomId);

		if (Objects.isNull(obj)) {
			if (num < 0L) {
				redisTemplate.opsForValue().set("live:count:" + roomId, 0L, 2, TimeUnit.DAYS);
				return new R(0L);
			} else {
				redisTemplate.opsForValue().set("live:count:" + roomId, num, 2, TimeUnit.DAYS);
				return new R(num);
			}
		}
		Long count = (Long) obj;
		Long result = count + num;

		if (result < 0L) {
			redisTemplate.opsForValue().set("live:count:" + roomId, 0L, 2, TimeUnit.DAYS);
			//lock.unlock();
			return new R(0L);
		} else {
			redisTemplate.opsForValue().set("live:count:" + roomId, result, 2, TimeUnit.DAYS);
			//lock.unlock();
			return new R(result);
		}
	}

	@GetMapping("getRoomMemberCountV2")
	public R getRoomMemberCountV2(String roomId) throws Exception {
		Object obj = redisTemplate.opsForValue().get("live:count:" + roomId);
		if (Objects.isNull(obj)) {
			return new R(0L);
		}
		return new R((Long) obj);
	}

	@GetMapping("getLiveRoomMemberList")
	public R getLiveRoomMemberList(String roomId) {
		return new R((List<LiveMemberViewEntity>) redisTemplate.opsForValue().get("live:memberDetail:" + roomId));
	}

}
